package net.hn.hnms.sys.common.core.jackson;

import net.hn.hnms.sys.common.core.utils.StringUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;

/**
 * 统一处理时间类型，不再由各模块分别处理
 *
 * @author Jiangmf
 * @date 2019-11-22
 */
public class DateTimeConverter {

    public static final String DATE_TIME_FORMAT_WITH_TIMEZONE = "yyyy-MM-dd'T'HH:mm:ssXXX";
    public static final String DATE_HOUR_WITH_TIMEZONE = "yyyy-MM-dd'T'HH:00:00XXX";
    public static final String DATE_FORMAT_WITHOUT_TIMEZONE = "yyyy-MM-dd";
    private static final String DATE_TIME_FORMAT_WITHOUT_TIMEZONE = "yyyy-MM-dd HH:mm:ss";
    private static final String DATE_HOUR_WITHOUT_TIMEZONE = "yyyy-MM-dd HH:00:00";
    public static final DateTimeFormatter DATE_TIME_FORMATTER_WITH_TIMEZONE = DateTimeFormatter.ofPattern(
            DATE_TIME_FORMAT_WITH_TIMEZONE).withZone(ZoneOffset.UTC);
    public static final DateTimeFormatter DATE_HOUR_FORMATTER_WITH_TIMEZONE = DateTimeFormatter.ofPattern(
            DATE_HOUR_WITH_TIMEZONE).withZone(ZoneOffset.UTC);
    public static final DateTimeFormatter DATE_TIME_FORMATTER_WITHOUT_TIMEZONE = DateTimeFormatter.ofPattern(
            DATE_TIME_FORMAT_WITHOUT_TIMEZONE).withZone(TimeZone.getDefault().toZoneId());
    public static final DateTimeFormatter DATE_FORMATTER_WITHOUT_TIMEZONE = DateTimeFormatter.ofPattern(
            DATE_FORMAT_WITHOUT_TIMEZONE).withZone(TimeZone.getDefault().toZoneId());
    public static final DateTimeFormatter DATE_HOUR_FORMATTER_WITHOUT_TIMEZONE = DateTimeFormatter.ofPattern(
            DATE_HOUR_WITHOUT_TIMEZONE).withZone(TimeZone.getDefault().toZoneId());

    private static InstantToString InstantToString;
    private static StringToInstant StringToInstant;
    private static LocalDateTimeToString LocalDateTimeToString;
    private static StringToLocalDateTime StringToLocalDateTime;
    private static LocalDateToString LocalDateToString;
    private static StringToLocalDate StringToLocalDate;

    /**
     * 获取InstantToString转换器
     */
    public static Converter<Instant, String> getInstantToString() {
        if (InstantToString == null) {
            synchronized (InstantToString.class) {
                if (InstantToString == null) {
                    InstantToString = new InstantToString();
                }
            }
        }
        return InstantToString;
    }

    /**
     * 获取StringToInstant转换器
     */
    public static Converter<String, Instant> getStringToInstant() {
        if (StringToInstant == null) {
            synchronized (StringToInstant.class) {
                if (StringToInstant == null) {
                    StringToInstant = new StringToInstant();
                }
            }
        }
        return StringToInstant;
    }

    /**
     * 获取LocalDateTimeToString转换器
     */
    public static Converter<LocalDateTime, String> getLocalDateTimeToString() {
        if (LocalDateTimeToString == null) {
            synchronized (LocalDateTimeToString.class) {
                if (LocalDateTimeToString == null) {
                    LocalDateTimeToString = new LocalDateTimeToString();
                }
            }
        }
        return LocalDateTimeToString;
    }

    /**
     * 获取StringToLocalDateTime转换器
     */
    public static Converter<String, LocalDateTime> getStringToLocalDateTime() {
        if (StringToLocalDateTime == null) {
            synchronized (StringToLocalDateTime.class) {
                if (StringToLocalDateTime == null) {
                    StringToLocalDateTime = new StringToLocalDateTime();
                }
            }
        }
        return StringToLocalDateTime;
    }

    /**
     * 获取LocalDateToString转换器
     */
    public static Converter<LocalDate, String> getLocalDateToString() {
        if (LocalDateToString == null) {
            synchronized (LocalDateToString.class) {
                if (LocalDateToString == null) {
                    LocalDateToString = new LocalDateToString();
                }
            }
        }
        return LocalDateToString;
    }

    /**
     * 获取StringToLocalDate转换器
     */
    public static Converter<String, LocalDate> getStringToLocalDate() {
        if (StringToLocalDate == null) {
            synchronized (StringToLocalDate.class) {
                if (StringToLocalDate == null) {
                    StringToLocalDate = new StringToLocalDate();
                }
            }
        }
        return StringToLocalDate;
    }

//============================================================================

    /**
     * 转换Instant到String
     */
    public static class InstantToString implements Converter<Instant, String> {

        private InstantToString() {
        }

        @Override
        public String convert(@Nullable Instant instant) {
            if (instant == null) {
                return null;
            }
            return DATE_TIME_FORMATTER_WITH_TIMEZONE.format(instant);
        }
    }

    /**
     * 转换String到Instant
     */
    public static class StringToInstant implements Converter<String, Instant> {

        private StringToInstant() {
        }

        @Override
        public Instant convert(@Nullable String s) {
            Instant instant;
            if (StringUtils.isBlank(s)) {
                return null;
            } else {
                try {
                    instant = Instant.from(DATE_TIME_FORMATTER_WITH_TIMEZONE.parse(s));
                } catch (DateTimeException e) {
                    instant = Instant.from(DATE_TIME_FORMATTER_WITHOUT_TIMEZONE.parse(s));
                }
                return instant;
            }
        }
    }

    /**
     * 转换String到LocalDateTime
     */
    public static class StringToLocalDateTime implements Converter<String, LocalDateTime> {

        private StringToLocalDateTime() {
        }

        @Override
        public LocalDateTime convert(@Nullable String s) {
            LocalDateTime localDateTime;
            if (StringUtils.isBlank(s)) {
                return null;
            } else {
                try {
                    localDateTime = LocalDateTime.parse(s, DATE_TIME_FORMATTER_WITH_TIMEZONE);
                } catch (DateTimeException e) {
                    localDateTime = LocalDateTime.parse(s,
                            DATE_TIME_FORMATTER_WITHOUT_TIMEZONE);
                }
                return localDateTime;
            }
        }
    }

    /**
     * 转换LocalDateTime到String
     */
    public static class LocalDateTimeToString implements Converter<LocalDateTime, String> {

        private LocalDateTimeToString() {
        }

        @Override
        public String convert(@Nullable LocalDateTime localDateTime) {
            if (localDateTime == null) {
                return null;
            }
            return localDateTime.format(DATE_TIME_FORMATTER_WITHOUT_TIMEZONE);
        }
    }

    /**
     * 转换String到LocalDate
     */
    public static class StringToLocalDate implements Converter<String, LocalDate> {

        private StringToLocalDate() {
        }

        @Override
        public LocalDate convert(@Nullable String s) {
            LocalDate localDate;
            if (StringUtils.isBlank(s)) {
                return null;
            } else {
                localDate = LocalDate.parse(s,
                        DATE_FORMATTER_WITHOUT_TIMEZONE);
                return localDate;
            }
        }
    }

    /**
     * 转换LocalDate到String
     */
    public static class LocalDateToString implements Converter<LocalDate, String> {

        private LocalDateToString() {
        }

        @Override
        public String convert(@Nullable LocalDate localDate) {
            if (localDate == null) {
                return null;
            }
            return localDate.format(DATE_FORMATTER_WITHOUT_TIMEZONE);
        }
    }
}

